import jsonpath

from utils.log_util import logger


class AssertUtil:
    @staticmethod
    # expect_value 预期结果
    def equals(actual_value, expect_value):
        """
        用于判断actual_value与expect_value是否相等。
        如果相等则返回True，否则返回False。
        """
        result = actual_value == expect_value
        if result:
            logger.info(f'断言成功！{actual_value} == {expect_value}')
            assert actual_value == expect_value
        else:
            logger.info(f"断言失败！实际值 '{actual_value}' 不等于预期值 '{expect_value}'。")
            assert actual_value == expect_value

    @staticmethod
    def less_than(actual_value, expect_value):
        """小于"""
        assert actual_value < expect_value, f'{actual_value} < {expect_value})'

    @staticmethod
    def less_than_or_equals(actual_value, expect_value):
        """小于等于"""
        assert actual_value <= expect_value, f'{actual_value} <= {expect_value})'

    @staticmethod
    def greater_than(actual_value, expect_value):
        """大于"""
        assert actual_value > expect_value, f'{actual_value} > {expect_value})'

    @staticmethod
    def greater_than_or_equals(actual_value, expect_value):
        """大于等于"""
        assert actual_value >= expect_value, f'{actual_value} >= {expect_value})'

    @staticmethod
    def not_equals(actual_value, expect_value):
        """不等于"""
        assert actual_value != expect_value, f'{actual_value} != {expect_value})'

    @staticmethod
    def contains(actual_value, expect_value):
        """
        用于判断expect_value是否包含在actual_value中。
        如果包含则返回True，否则返回False。
        """
        try:
            if expect_value in actual_value:
                logger.info(f'断言成功！{expect_value} in {actual_value}')
                return True
            else:
                logger.info(f"断言失败！预期值 '{expect_value}' 不在实际值 '{actual_value}' 中。")
                return False
        except TypeError:
            logger.info(
                f"断言失败！actual_value类型为{type(actual_value)}，expect_value类型为{type(expect_value)}，请检校验查参数数据类型")
            # 直接 return False pytest 认为是成功的
            assert 1 == 2

    @staticmethod
    def startswith(actual_value, expect_value):
        """以什么开头"""
        assert str(actual_value).startswith(str(expect_value)), f'{str(actual_value)} startswith {str(expect_value)})'

    @staticmethod
    def endswith(actual_value, expect_value):
        """以什么结尾"""
        assert str(actual_value).endswith(str(expect_value)), f'{str(actual_value)} endswith {str(expect_value)})'

    @staticmethod
    def length(actual_value, expect_value):
        """校验数量"""
        if not isinstance(actual_value, list):
            actual_value = [actual_value]
        assert len(actual_value) == expect_value, f'{str(actual_value)} == {str(expect_value)})'

    def extract_by_jsonpath(self, extract_value: dict, extract_expression: str):
        """
        根据接口返回json内容提取校验的实际结果
        :param extract_value: dict 需要提取的数据
        :param extract_expression: jsonpath提取表达式 $.errcode
        :return:
        """
        if not isinstance(extract_expression, str):  # 非字符串时直接返回 extract_expression
            return extract_expression
        extract_data = jsonpath.jsonpath(extract_value, extract_expression)
        if not extract_expression:  # "" 空字符串返回 extract_expression
            return
        elif len(extract_data) == 1:  # 有内容，列表只有一个元素，需要下标取值返回
            return extract_data[0]
        else:  # 正常传入数据和jsonpath表达式
            return extract_data

    def validate_response(self, response, validate_check: list):
        """
        校验结果
        :param response: 接口返回得json格式数据
        :param validate_check:list yaml文件的validate部分数据 [{'contains':['$.errcode','0']},{'contains':['$.errmsg','updated']}]
        :return:
        """
        for check in validate_check:  # 遍历外层列表
            for check_type, check_value in check.items():  # 遍历嵌套字典，value遍历出来为列表
                # 实际结果,从接口返回的json格式数据中提取数据,check_value[0]为jsonpath表达式
                actual_value = self.extract_by_jsonpath(response, check_value[0])
                # 预期结果
                expect_value = check_value[1]
                # 调用断言
                logger.info(
                    f'测试用例断言:\n实际结果actual_value>>>{actual_value} {type(actual_value)}\n预期结果expect_value>>>{expect_value} {type(expect_value)}')
                if check_type in ["eq", "equals", "equal"]:
                    self.equals(actual_value, expect_value)
                elif check_type in ["lt", "less_than"]:
                    self.less_than(actual_value, expect_value)
                elif check_type in ["le", "less_or_equals"]:
                    self.less_than_or_equals(actual_value, expect_value)
                elif check_type in ["gt", "greater_than"]:
                    self.greater_than(actual_value, expect_value)
                elif check_type in ["ne", "not_equal"]:
                    self.not_equals(actual_value, expect_value)
                elif check_type in ["contains", "con"]:
                    self.contains(actual_value, expect_value)
                elif check_type in ["startswith"]:
                    self.startswith(actual_value, expect_value)
                elif check_type in ["endswith"]:
                    self.endswith(actual_value, expect_value)
                elif check_type in ["length"]:
                    self.length(actual_value, expect_value)
                else:
                    logger.info(f'{check_type}  测试数据中的断言类型不存在定义中，请检查 ../utils/assert_util.py')


AssertUtil = AssertUtil()
